package com.fitapp;

import java.util.ArrayList;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.ContentValues;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.Color;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.media.MediaPlayer;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Bundle;
import android.os.SystemClock;
import android.view.Menu;
import android.view.View;
import android.widget.Button;
import android.widget.Chronometer;
import android.widget.TextView;

import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.MapFragment;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.LatLngBounds;
import com.google.android.gms.maps.model.PolylineOptions;

public class RunActivity extends Activity
{
	private Button btnStart;
	private Button btnStop;
	private Chronometer cmStopWatch;
	public GoogleMap googleMap;
	private PolylineOptions trackOptions = new PolylineOptions( );
	private ArrayList< LatLng > coord = new ArrayList< LatLng >( );
	private LocationManager locationManager;
	private LocationListener locationListener;
	private double distance;
	private LatLng lastPoint;
	private float[ ] addDis;
	private DatabaseHelper helper = new DatabaseHelper( this );
	private MediaPlayer mPlayer;
	private String waypoints;
	private double lat;
	private double lon;
	private LatLng newLatLng;
	private Location loc;
	private float avgSpeed;
	private SQLiteDatabase db;
	private String query;
	private Cursor cursor;
	private long runTime;
	private ContentValues values;
	private int unixTime;

	@Override
	protected void onCreate( Bundle savedInstanceState )
	{
		super.onCreate( savedInstanceState );
		setContentView( R.layout.activity_run );
		// Location Manager needs to be initialized at start to center Map
		// correctly on last known location
		// Acquire a reference to the system Location Manager
		googleMap = ( (MapFragment) getFragmentManager( ).findFragmentById( R.id.map ) ).getMap( );
		locationManager = (LocationManager) this.getSystemService( Context.LOCATION_SERVICE );
		loc = locationManager.getLastKnownLocation( LocationManager.NETWORK_PROVIDER );
		if( loc != null )
		{
			newLatLng = new LatLng( loc.getLatitude( ), loc.getLongitude( ) );
			// Init gui elements
			googleMap.moveCamera( CameraUpdateFactory.newLatLngZoom( newLatLng, 16 ) );
		}
		// Initialize Elements
		btnStart = (Button) findViewById( R.id.btnStartRun );
		btnStop = (Button) findViewById( R.id.btnStopRun );
		btnStart.setTextColor( Color.GREEN );
		btnStop.setTextColor( Color.GRAY );
		btnStop.setEnabled( false );
		cmStopWatch = (Chronometer) findViewById( R.id.cmStopWatch );
		distance = 0;
		addDis = new float[ 3 ];
		// In Case Old Workout should be printed

		// Warn in case no Internet connection is established as gmaps needs
		// data
		if( !isOnline( ) )
		{
			buildAlertMessageNoInternet( );
		}

		Intent intent = getIntent( );
		if( intent.getExtras( ) != null )
		{
			btnStart.setEnabled( false );
			btnStop.setEnabled( false );
			loadOldTrack( intent.getIntExtra( "id", 1 ) );
		}
		else
		{
			// Check GPS enabled
			if( !locationManager.isProviderEnabled( LocationManager.GPS_PROVIDER ) )
			{
				buildAlertMessageNoGps( );
			}
		}
	}

	public void loadOldTrack( int id )
	{ // Load Workout from History
		waypoints = new String( );
		helper = new DatabaseHelper( this );
		db = helper.getReadableDatabase( );
		query = new String( "SELECT Trackpoints FROM Activities WHERE Id = " + id );
		cursor = db.rawQuery( query, null );
		cursor.moveToFirst( );
		waypoints = cursor.getString( 0 ); // String of format
		// "LatLng (Latitude,Longitude)" that
		// needs to be parsed
		db.close( );
		helper.close( );
		waypoints = waypoints.substring( 1, waypoints.length( ) - 1 );
		String[ ] values = new String[ 2 ];
		while( waypoints.length( ) > 45 )
		{ // There are more then 2 Waypoints left in the string
			values = waypoints.split( ", ", 2 ); // Split between "LatLng ," and
			// "(Latitude,Longitude)"
			addToCoord( values[ 0 ] );
			if( waypoints.length( ) < 70 )
			{ // Only 2 Waypoints left in string
				addToCoord( values[ 1 ] );
				break; // Added all Waypoints
			}
			else
			{
				waypoints = values[ 1 ];
			}
		}
		helper = new DatabaseHelper( this );
		db = helper.getReadableDatabase( );
		cursor = db.rawQuery( "SELECT Time, Count FROM Activities Where Id = " + id, null );
		if( cursor.getCount( ) > 0 )
		{
			cursor.moveToFirst( );
			runTime = Integer.parseInt( cursor.getString( 0 ) );
			distance = Double.parseDouble( cursor.getString( 1 ) );
			showSummary( runTime );
		}
		cursor.close( );

		if( coord.size( ) > 0 )
		{
			googleMap.moveCamera( CameraUpdateFactory.newLatLngZoom( coord.get( 0 ), 10 ) ); // Move
			                                                                                 // to
			                                                                                 // startpoint
		}
	}

	public void addToCoord( String s )
	{
		s = s.substring( 10, s.length( ) - 1 ); // Remove opening/closing
		// brackets
		String[ ] latlng = s.split( "," ); // Split on Latitude/Longitude
		// seperator
		lat = Double.parseDouble( latlng[ 0 ] );
		lon = Double.parseDouble( latlng[ 1 ] );
		addTrackpoint( lat, lon ); // Draw line
		coord.add( new LatLng( lat, lon ) );
	}

	@Override
	public boolean onCreateOptionsMenu( Menu menu )
	{
		return true;
	}

	public void onBtnStartClicked( View view )
	{
		// Init and start timer afterwards
		cmStopWatch.setBase( SystemClock.elapsedRealtime( ) );
		cmStopWatch.start( );
		btnStart.setEnabled( false );
		btnStop.setEnabled( true );
		btnStart.setTextColor( Color.GRAY );
		btnStop.setTextColor( Color.GREEN );
		// Start tracking GPS data
		getGPSdata( );
	}

	public void onBtnStopClicked( View view )
	{
		// Stop timer
		cmStopWatch.stop( );
		btnStop.setEnabled( false );
		btnStart.setTextColor( Color.GRAY );
		btnStop.setTextColor( Color.GRAY );
		// Show Resulting Distance and Time as Toast
		long runTime = ( ( SystemClock.elapsedRealtime( ) - cmStopWatch.getBase( ) ) / 1000 );
		showSummary( runTime );
		// Stop Location listener
		String waypoints = coord.toString( );
		// Write to Database
		helper = new DatabaseHelper( this );
		db = helper.getWritableDatabase( );
		values = new ContentValues( );
		unixTime = (int) ( System.currentTimeMillis( ) / 1000L );
		values.put( "Type", DatabaseHelper.TYPE_RUNNING );
		values.put( "Count", distance );
		values.put( "Date", unixTime );
		values.put( "Trackpoints", waypoints );
		values.put( "Time", runTime );
		db.insert( "Activities", null, values );

		Cursor c = db.rawQuery( "SELECT * FROM Goals WHERE Type=? LIMIT 1", new String[ ] { "running" } );
		c.moveToFirst( );
		int reached = Integer.parseInt( c.getString( 3 ) );
		values = new ContentValues( );
		values.put( "Reached", reached + distance );
		db.update( "Goals", values, "Type=?", new String[ ] { "running" } );
		db.close( );

		// Center Map to the track Boundaries
		centerMap( );

		mPlayer = MediaPlayer.create( this, R.raw.nice_one );
		mPlayer.start( );
		killGps( );
	}

	private void showSummary( long runTime )
	{
		if( runTime > 0 )
		{
			avgSpeed = (float) ( distance / runTime );
		}
		else
		{
			avgSpeed = 0;
		}
		// Write result below map
		int min = (int) runTime / 60;
		if( min != 0 )
		{
			runTime = runTime % ( min * 60 );
		}
		( (TextView) findViewById( R.id.resultView ) ).setText( "You tracked " + (int) distance + " Meters in " + min + " Minutes and " + runTime + " Seconds! Average Speed: " + avgSpeed + " Meters/Second" );
	}

	private void centerMap()
	{
		if( coord.size( ) > 0 )
		{
			// First coord is min and max
			LatLng min = coord.get( 0 );
			LatLng max = coord.get( 0 );

			// Find minimum and maximum
			for( int i = 1; i < coord.size( ); i++ )
			{
				if( coord.get( i ).latitude < min.latitude )
				{
					min = new LatLng( coord.get( i ).latitude, min.longitude );
				}
				if( coord.get( i ).longitude < min.longitude )
				{
					min = new LatLng( min.latitude, coord.get( i ).longitude );
				}

				if( coord.get( i ).latitude > max.latitude )
				{
					max = new LatLng( coord.get( i ).latitude, max.longitude );
				}
				if( coord.get( i ).longitude > max.longitude )
				{
					max = new LatLng( max.latitude, coord.get( i ).longitude );
				}
			}

			LatLngBounds track = new LatLngBounds( min, max );
			// Set the camera to the greatest possible zoom level that includes
			// the bounds
			googleMap.moveCamera( CameraUpdateFactory.newLatLngBounds( track, 0 ) );
		}
	}

	public void addTrackpoint( double longitude, double latitude )
	{
		// Draw a line
		trackOptions.add( new LatLng( longitude, latitude ) );
		googleMap.addPolyline( trackOptions );
	}

	public void getGPSdata()
	{

		// Define a listener that responds to location updates
		locationListener = new LocationListener( )
		{
			public void onLocationChanged( Location location )
			{
				// Called when a new location is found by the location provider.
				LatLng ll = new LatLng( location.getLatitude( ), location.getLongitude( ) );
				coord.add( ll ); // Add to list of all waypoints
				// Draw line from new Waypoint to last one
				addTrackpoint( location.getLatitude( ), location.getLongitude( ) );
				// Center Map at current location
				googleMap.moveCamera( CameraUpdateFactory.newLatLngZoom( ll, 18 ) );
				// If last point exists, calculate Distance
				if( lastPoint != null )
				{
					Location.distanceBetween( lastPoint.latitude, lastPoint.longitude, ll.latitude, ll.longitude, addDis );
					distance += addDis[ 0 ];
				}
				lastPoint = ll;
			}

			public void onStatusChanged( String provider, int status, Bundle extras )
			{
			}

			public void onProviderEnabled( String provider )
			{
			}

			public void onProviderDisabled( String provider )
			{
			}
		};

		if( !locationManager.isProviderEnabled( LocationManager.GPS_PROVIDER ) )
		{
			buildAlertMessageNoGps( );
		}

		// Register the listener with the Location Manager to receive location
		// updates every 10 Seconds when Person moved >20m
		locationManager.requestLocationUpdates( LocationManager.GPS_PROVIDER, 10000, 20, locationListener );
	}

	private void buildAlertMessageNoGps()
	{
		final AlertDialog.Builder builder = new AlertDialog.Builder( this );
		builder.setMessage( "Your GPS seems to be disabled, do you want to enable it?" ).setCancelable( false ).setPositiveButton( "Yes", new DialogInterface.OnClickListener( )
		{
			public void onClick( final DialogInterface dialog, final int id )
			{
				startActivity( new Intent( android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS ) );
			}
		} ).setNegativeButton( "No", new DialogInterface.OnClickListener( )
		{
			public void onClick( final DialogInterface dialog, final int id )
			{
				dialog.cancel( );
			}
		} );
		final AlertDialog alert = builder.create( );
		alert.show( );
	}

	private void buildAlertMessageNoInternet()
	{
		final AlertDialog.Builder builder = new AlertDialog.Builder( this );
		builder.setMessage( "You don't seem to have Internet connection. Do you want to fix that?" ).setCancelable( true ).setPositiveButton( "Yes", new DialogInterface.OnClickListener( )
		{
			public void onClick( final DialogInterface dialog, final int id )
			{
				startActivity( new Intent( android.provider.Settings.ACTION_SETTINGS ) );
			}
		} ).setNegativeButton( "No", new DialogInterface.OnClickListener( )
		{
			public void onClick( final DialogInterface dialog, final int id )
			{
				dialog.cancel( );
			}
		} );
		final AlertDialog alert = builder.create( );
		alert.show( );
	}

	private void killGps()
	{
		locationManager.removeUpdates( locationListener );
		locationManager = null;
	}

	public void onPause()
	{
		super.onPause( );
		if( mPlayer != null )
		{
			mPlayer.release( );
		}
	}

	/**
	 * Check for valid internet connection on the device
	 * 
	 */
	public boolean isOnline()
	{
		ConnectivityManager cm = (ConnectivityManager) getSystemService( Context.CONNECTIVITY_SERVICE );
		NetworkInfo netInfo = cm.getActiveNetworkInfo( );
		if( netInfo != null && netInfo.isConnectedOrConnecting( ) )
		{
			return true;
		}
		return false;
	}
}